/****************************************************************************
* Copyright (c) 2008, j. montgomery, ATGi                                   *
* All rights reserved.                                                      *
*                                                                           *
* Redistribution and use in source and binary forms, with or without        *
* modification, are permitted provided that the following conditions        *
* are met:                                                                  *
*                                                                           *
* - Redistributions of source code must retain the above copyright          *
*   notice, this list of conditions and the following disclaimer.           *
*                                                                           *
* - Redistributions in binary form must reproduce the above                 *
*   copyright notice, this list of conditions and the following             *
*   disclaimer in the documentation and/or other materials provided         *
*   with the distribution.                                                  *
*                                                                           *
* - Neither the name of ATGi nor the names of its contributors may          *
*   be used to endorse or promote products derived from this software       *
*   without specific prior written permission.                              *
*                                                                           *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES                  *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR        *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)        *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)             *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED       *
* OF THE POSSIBILITY OF SUCH DAMAGE.                                        *
*****************************************************************************
*/
using System;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Xml;

namespace DnSmtp.Message
{
	public class MailMessageSectionHandler : IConfigurationSectionHandler
	{
		public MailMessageSectionHandler()
		{
		}

		
		public object Create(
			object parent,
			object configContext,
			XmlNode section)
		{
			MailMessageDictionary messages = new MailMessageDictionary();
			
			// Parse the configuration section like a "messageGroup" element with no uplevel fields.
			ParseMessageGroup(messages, new Hashtable(), section as XmlElement);

			return messages;
		}

		
		private void ParseMessageGroup(
			MailMessageDictionary messages,
			IDictionary upLevelFields,
			XmlElement section)
		{
			// Store specified group fields in the dictionary of uplevel fields.
			AddSectionFieldsToCollection(upLevelFields, section);

			// Recursively parse child message groups.
			foreach (XmlElement childMessageGroupElement in section.SelectNodes("./messageGroup"))
			{
				// Create a new field dictionary containing all uplevel fields.
				IDictionary fields = new Hashtable(upLevelFields);

				// Parse the message group, adding all returned messages to the return collection.
				ParseMessageGroup(messages, fields, childMessageGroupElement);
			}

			// Parse child messages.
			foreach (XmlElement childMessageElement in section.SelectNodes("./message"))
			{
				// Create a new field dictionary containing all uplevel fields.
				IDictionary fields = new Hashtable(upLevelFields);

				// Parse the message, adding returned message to the return collection.
				ParseMessage(messages, fields, childMessageElement);
			}
		}

		
		private void ParseMessage(
			MailMessageDictionary messages,
			IDictionary upLevelFields,
			XmlElement section)
		{
			// Declare working objects.
			MailMessage message = new MailMessage();

			// Store fields in the dictionary of uplevel fields.
			AddSectionFieldsToCollection(upLevelFields, section);

			// Set properties of the message based on current field settings.
			StringWriter bodyWriter = new StringWriter();
			string header = Convert.ToString(upLevelFields["header"]).Trim();
			string body = Convert.ToString(upLevelFields["body"]).Trim();
			string footer = Convert.ToString(upLevelFields["footer"]).Trim();

			if (!header.Equals(string.Empty))
			{
				bodyWriter.WriteLine(header);
				bodyWriter.WriteLine();
			}

			if (!body.Equals(string.Empty))
			{
				bodyWriter.WriteLine(body);
				bodyWriter.WriteLine();
			}

			if (!footer.Equals(string.Empty))
			{
				bodyWriter.WriteLine(footer);
			}
			
			// TODO: Parse more properties of the message.
			message.FromAddress = EmailAddress.Parse(Convert.ToString(upLevelFields["fromAddress"]).Trim());
			message.Subject = Convert.ToString(upLevelFields["subject"]).Trim();
			message.AddTextMessage(bodyWriter.ToString());

			messages.Add(upLevelFields["id"], message);
		}

		
		private void AddSectionFieldsToCollection(
			IDictionary fields,
			XmlElement section)
		{
			// - All attributes are message fields.
			foreach (XmlAttribute attribute in section.Attributes)
			{
				fields[attribute.Name] = attribute.Value;
			}

			// - All elements that are not messages or message groups are also message fields.
			foreach (XmlElement childElement in section.SelectNodes("./*[name() != 'messageGroup' and name() != 'message']"))
			{
				fields[childElement.Name] = childElement.InnerXml;
			}
		}
	}
}
